package com.well.kernel.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.well.kernel.spring.web.ResponseData;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.util.*;

/**
 * Copyright &copy; Well All rights reserved.
 * Author:Well
 * Date:2017-02-05
 * Description:Web 的利用类，包括request和response
 */

public class WebUtil {
    private static Logger logger=Logger.getLogger(WebUtil.class);

    private WebUtil(){}

    /**
     * 获取前台请求的字符串值
     * @param request
     * @param name 前台请求的参数名称
     * @return
     */
    public static String getString(ServletRequest request,String name)
    {
        return request.getParameter(name);
    }

    /**
     * 获取前台请求的字符串数组
     * @param request
     * @param name 前台请求的参数名称
     * @return
     */
    public static String[] getStrings(ServletRequest request,String name)
    {
        return request.getParameterValues(name);
    }

    /**
     * 获取前台请求的字符串列表
     * @param request
     * @param name 前台请求的参数名称
     * @return
     */
    public static List<String> getStringList(ServletRequest request,String name)
    {
        List<String> stringList = null;
        String[] strings=getStrings(request, name);
        if(null!=strings)
        {
            stringList= Arrays.asList(strings);
        }
        return stringList;
    }

    /**
     * 获取请求推送的json数据，编码为 UTF-8
     * @param request
     * @return
     */
    public static String getJSON(ServletRequest request){
        return getJSON(request,"UTF-8");
    }

    /**
     * 获取请求推送的json数据
     * @param request
     * @param encoding
     * @return
     */
    public static String getJSON(ServletRequest request,String encoding){
        String json=null;
        try{
            json= IOUtils.toString(request.getInputStream(), encoding);
        }catch(IOException e){
            logger.error(e);
        }
        return json;
    }

    /**
     * 获取请求的uri
     * 例如：/user/login
     * @param request
     * @return
     */
    public static String getURI(HttpServletRequest request){
        return request.getRequestURI();
    }

    /**
     * 获取请求的ur
     * 例如：http://127.0.0.1/user/login
     * @param request
     * @return
     */
    public static String getURL(HttpServletRequest request){
        return request.getRequestURL().toString();
    }

    /**
     * 获取绝对根路径
     * @param request
     * @return
     */
    public static String getRealPath(HttpServletRequest request){
        return getRealPath(request,"/");
    }

    /**
     * 获取相对于根路径的绝对路径
     * @param request
     * @param path 相对于根路径的相对路径
     * @return
     */
    public static String getRealPath(HttpServletRequest request,String path) {
        return request.getSession().getServletContext().getRealPath(path);
    }

    /**
     * 获取请求的 session id
     * @param request
     * @return
     */
    public static String getSessionID(HttpServletRequest request){
        return request.getSession(true).getId();
    }

    /**
     * 判断是否为 ajax 请求
     * @param request
     * @return
     */
    public static boolean isAjax(HttpServletRequest request)
    {
        String header=request.getHeader("x-requested-with");
        if(StringUtils.equalsIgnoreCase(header, "XMLHttpRequest"))
        {
            return true;
        }
        return false;
    }

    /**
     * 获取请求的IP地址
     * 经过下面一系列的代理，IP地址会发生改变
     *  X-Forwarded-For,Proxy-Client-IP,WL-Proxy-Client-IP
     *  HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR 这两个
     * @param request
     * @return 前台请求的IP地址
     * 		        出现异常返回null
     */
    public static String getIP(HttpServletRequest request)
    {
        String ip = null;
        try
        {
            String[] proxys = { "x_forwarded_for", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR" };
            for (String proxy : proxys)
            {
                ip = request.getHeader(proxy);
                if (StringUtils.isBlank(ip) || "unkown".equalsIgnoreCase(ip))
                {
                    continue;
                }
                else
                {
                    break;
                }
            }
            if (null != ip && ip.length() > 15)
            {
                int index = ip.indexOf(",");
                if (index > 0)
                {
                    ip = ip.substring(0, index);
                }
            }
            if (StringUtils.isBlank(ip) || "unkown".equalsIgnoreCase(ip))
            {
                ip = request.getRemoteAddr();
            }
        }
        catch (Exception e)
        {
            logger.error(e);
        }
        return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
    }

    /**
     * 判断请求的IP是否在IP白名单中
     * true-在IP白名单中，可以访问
     * false-不在IP白名单中，不能访问
     * @param request
     * @param whiteList 白名单
     * @return
     */
    public static boolean isInIPWhiteList(HttpServletRequest request,Set<String> whiteList){
        if(null==whiteList || whiteList.size()==0){
            logger.debug("没有设置IP白名单，所有IP均可访问");
            return true;
        }
        String ip=getIP(request);
        for(String s:whiteList){
            if(StringUtils.equals(s,ip)){
                return true;
            }
        }
        logger.debug("IP【"+ip+"】不在白名单中");
        return false;
    }

    /**
     * 判断请求的IP是否在IP黑名单中
     * true-在IP黑名单中，不能访问
     * false-不在IP白名单中，可以访问
     * @param request
     * @param blackList 黑名单
     * @return
     */
    public static boolean isInIPBlackList(HttpServletRequest request,Set<String> blackList){
        if(null==blackList || blackList.size()==0){
            logger.debug("没有设置IP黑名单，所有IP均可访问");
        }
        String ip=getIP(request);
        for(String s:blackList){
            if(StringUtils.equals(s,ip)){
                return true;
            }
        }
        logger.debug("IP【"+ip+"】不在黑名单中");
        return false;
    }

    /* 访问的计数器 */
    private static Map<String,Integer> counterMap=new HashMap<>();
    /* 每小时的毫秒数 */
    private static int hourMillie=60*60*1000;
    /**
     * 限制频率，在 limitHour 时间段内，只能访问 limitCount 次
     * @param request
     * @param limitCount 限制次数
     * @param limitHour 限制时间，单位：小时
     */
    public static void limitFrequency(HttpServletRequest request,int limitCount,int limitHour){
        String ip=getIP(request);
        String url=getURL(request);
        final String key="request_"+ip+"_"+url;
        Integer count=counterMap.get(key);
        if(null==count){
            count=1;
            /* 开始计时 */
            Timer timer=new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    logger.debug("删除【" + key + "】的访问次数");
                    counterMap.remove(key);
                }
            },limitHour*hourMillie);
        }else{
            if(count>=limitCount){
                String message="【"+ip+"】访问【"+url+"】超过【"+limitCount+"】次！";
                logger.error(message);
                throw new RuntimeException(message);
            }
            count++;
        }
        counterMap.put(key,count);
    }

    /**
     * 发送 responseData 对象到前台
     * @param response
     * @param responseData
     */
    public static void renderResponseData(HttpServletResponse response,ResponseData responseData)
    {
        try
        {
            ObjectMapper mapper = new ObjectMapper();
            String json=mapper.writeValueAsString(responseData);
            renderJSON(response,json);
        }
        catch (Exception e)
        {
            logger.error(e);
        }
    }

    /**
     * 发送 json 内容
     * @param response 响应
     * @param content json格式的内容
     */
    public static void renderJSON(HttpServletResponse response, String content)
    {
        render(response, "application/json;charset=UTF-8", content);
    }

    /**
     * 发送指定contentType类型的内容到前台
     * @param response 响应
     * @param contentType 类型
     * @param content 内容
     */
    public static void render(HttpServletResponse response,String contentType,String content)
    {
        PrintWriter writer=null;
        try
        {
            setProperty(response, contentType);
            writer=response.getWriter();
            writer.write(content);
        }
        catch (IOException e)
        {
            logger.error(e);
        }
        finally
        {
            if(null!=writer)
            {
                writer.flush();
                writer.close();
            }
        }
    }

    /**
     * 设置响应的属性
     * @param response
     * @param contentType
     */
    private static void setProperty(HttpServletResponse response,String contentType)
    {
        response.setCharacterEncoding("UTF-8");
        response.setContentType(contentType);
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-store");
        response.setDateHeader("Expires", 0);
    }

}
